package org.sgx.gwteditors.client.impl1.complex;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

//import org.sgx.gwteditors.client.editor.ComplexTypeEditor;
import org.sgx.gwteditors.client.editor.Editor;
import org.sgx.gwteditors.client.editor.EditorNotFound;
import org.sgx.gwteditors.client.editor.Types;
import org.sgx.gwteditors.client.editor.error.EditorError;
import org.sgx.gwteditors.client.editor.error.EditorErrorManager;
import org.sgx.gwteditors.client.editor.event.EditorEventManager;
import org.sgx.gwteditors.client.editor.event.EditorValueChangeEvent;
import org.sgx.gwteditors.client.editor.event.ValueChangeListener;
import org.sgx.gwteditors.client.impl1.EditorManager1;

import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Widget;

/**
 * matrix 2d editor, for any kind of value - all members must be of the same type
 * @author sg
 *
 */
public class Array2DEditor extends FlexTable 
	implements Editor<Object[][]>, ValueChangeListener<Object>{
	static Logger logger = Logger.getLogger(Array2DEditor.class+"");
	Map<String, Editor<Object>> eds = null;
	private int imax;
	private int jmax;
	private String type;
	
	public Array2DEditor(String type) {
		super();
		eds = new HashMap<String, Editor<Object>> ();
		this.type=type;
	}

	@Override
	public void addValueChangeListener(ValueChangeListener<Object[][]> l) {
		EditorEventManager.<Object[][]>getInstance().addValueChangeListener(this, l);
	}
	@Override
	public List<EditorError<Object[][]>> getErrors() {
		return EditorErrorManager.<Object[][]>getInstance().getErrors(this);
	}
	@Override
	public void removeValueChangeListener(ValueChangeListener<Object[][]> l) {
		EditorEventManager.<Object[][]>getInstance().addValueChangeListener(this, l);
	}

	@Override
	public Object[][] flush() {
		Object[][] vals = new Object[imax][jmax];
		for(int i=0; i<this.imax; i++) {
			for(int j=0; j<this.jmax; j++) {
				Editor<Object> ed = eds.get(i+","+j);
				if(ed==null)
					continue;
				Object val = ed.flush();
				vals[i][j]=val;
			}
		}			
		return vals;//no validation / errors
	}

	@Override
	public void load(Object[][] model) {
		if(model==null)
			return;
		//clear the table
		clear();
		this.imax=model.length;
		for(int i=0; i<model.length; i++) {
			if(model[i]==null)
				continue;
			this.jmax=model[i].length;
			for(int j=0; j<model[i].length; j++) {
				Object o = model[i][j];
				if(o==null)
					continue;
				Editor<Object> ed=null;
				try {
					ed = Types.getInstance().newEditor(type);//EditorFactoryImpl.<Object>getInstance().getEditorForObject(o);
					ed.load(o);
					EditorEventManager.getInstance().addValueChangeListener(ed, this);
					setWidget(i, j, ed.getWidget());
					eds.put(i+","+j, ed);
				} catch (EditorNotFound e) {
					logger.log(Level.WARNING, " exception building editor for field "+i+
							", "+j+", class: "+model[i][j].getClass()+" : "+o+
							". Cause: "+e.getCause()+" - "+e.getMessage());
					e.printStackTrace();
				}
			}
		}		
	}

	@Override
	public Widget getWidget() {
		return this;
	}

	@Override
	public void notifyValueChange(EditorValueChangeEvent<Object> evt) {
		//TODO: here we do not flush the value to the event. Pass null, the user must explicitly flush this editor.
		EditorValueChangeEvent<Object[][]> e_ = new EditorValueChangeEvent<Object[][]>(this, null, evt);
		EditorEventManager.<Object[][]>getInstance().fireValueChangeEvent(this, e_);	
	}

	@Override
	public boolean isSimple() {
		return false;
	}

	@Override
	public String getEditorId() {
		return EditorManager1.getInstance().getEditorName(this);		
	}

	@Override
	public String[] getEditorTypesSupported() {
		return null; //String[]{EditorFramework1.TYPE_}; 
	}

}
